#!/usr/bin/python -S
#
# Copyright (C) 2009 Andy Chu
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Documentation generator.

This takes test cases and outputs HTML for publishing.

TODO:

  - Some simple test cases
  - Syntax highlighting
  - It would be nice if I could highlight corresponding matches somehow, the
    depot path colored the same in the input-string as in the JSON

  - Put *subpatterns* on the same page somehow?
  - Put test case docstring on the page.
  - I should have one page per test case, with multiple assertions being
    multiple rows.
"""

__author__ = 'Andy Chu'

import os
import re
import sys

from pan.core import json
from pan.core import records
from pan.test import testy

# HACK, I'm copying jsontemplate into this repo for now.
from readonly import jsontemplate
import jsonpattern
from jsonpattern import highlight

__author__ = 'Andy Chu'


# Use jsontemplate to document itself!
_TEST_CASE_HTML = """
<style type=text/css>

/* Section where we display a pattern */
.pattern {
  border-style: solid none none none; 
  border-width: 1px;
  border-color: black;
  margin-bottom: 4em;
}

.desc-row {
  background-color: #DDD;
}

.pattern-row {
  background-color: #EEE;
}

.heading {
  font-weight: bold;
  color: darkblue;
}

/* Subpattern names */
.subpattern {
  color: #3B9C9C;
  /*color: darkred;*/
}

tr td {
  padding: 0.5em;
  vertical-align: top;
}

.key {
  color: blue;
}

.comment {
  color: green;
  font-style: italic;
}

/* Special JSON Pattern characters */
.special {
  color: purple;
}

</style>

{.repeated section verifications}
  <table width="100%" cellspacing="0" class="pattern">
    {.section desc}
    <tr class="desc-row">
      <td colspan="2">
        {@|raw}  {# This can have HTML}
      </td>
    </tr>
    {.end}

    <tr class="pattern-row">
      <td>
        <span class="heading">Pattern</span>
        {.section name}
          <code><span class="subpattern">{@|html}</span></code>
        {.end}
      </td>
      <td>
        <span class="heading">AST</span>
      </td>
    </tr>
    <tr class="pattern-row">
      <td>
        {pattern|raw}
      </td>
      <td>
        <pre>{ast|html}</pre>
      </td>
    </tr>

    <tr class="block">
      <td>
        <span class="heading">Input String</span>
      </td>
      <td>
        <span class="heading">Captured JSON</span>
      </td>
    </tr>

    <tr class="block">
      <td>
        <pre>{input-string}</pre>
      </td>
      <td>
        <pre>{captured|raw}</pre>
      </td>
  </table>

{.end}

<p><i>This HTML fragment was automatically generated from the <a
href="http://json-pattern.googlecode.com/svn/trunk/jsontemplate_test.py">test
cases</a> for <a href="http://code.google.com/p/json-pattern">JSON
Pattern</a>.  </p>
"""
# TODO: Fix link above


class DocGenerator(testy.StandardVerifier):

  def __init__(self, output_dir):
    testy.StandardVerifier.__init__(self)
    self.output_dir = output_dir

    # Counter for unique filenames
    self.counter = 1

    self.html_template = jsontemplate.Template(
        _TEST_CASE_HTML, default_formatter='html')

  def BeforeMethod(self, method):
    testy.StandardVerifier.BeforeMethod(self, method)
    # Reset the counter every time we get a method
    self.counter = 1
    self.verifications = []

  DICT_KEY_RE = re.compile('"([\w\-]+)":')

  def AfterMethod(self, method):
    verifications = []
    for pattern, s, captured in self.verifications:
      try:
        pattern_html = highlight.AsHtml(pattern.pattern_str)
      except Exception, e:
        print '!!!!!!!!', e  # HACK
        continue

      captured = json.dumps(captured, indent=2)
      # A little hack to highlight key names like they are in the pattern
      captured = self.DICT_KEY_RE.sub(
          r'"<span class="key">\1</span>":', captured)

      verifications.append({
          'pattern': pattern_html,
          'ast': pattern.AsTree(),
          'input-string': s,
          'captured': captured,
          'name': pattern.name,
          'desc': pattern.desc,
          })

    html = self.html_template.expand({'verifications': verifications})

    filename = '%s.html' % self.current_method.__name__
    self._WriteFile(filename, html)
    self.verifications = []  # reset for next method

  def Match(self, pattern_def, s, expected):
    """
    Args:
      pattern_def: testy.ClassDef instance.
      s: Input string
      expected: Expected dictionary
    """
    #tested_pattern = jsonpattern.Pattern(
    #    *pattern_def.args, **pattern_def.kwargs)
    # Can pass a simple string, or a class definition
    if isinstance(pattern_def, jsonpattern.Pattern):
      tested_pattern = pattern_def
      pattern_str = tested_pattern.pattern_str
    else:
      if isinstance(pattern_def, basestring):
        pattern_str = pattern_def
        kwargs = {}
      else:
        pattern_str = pattern_def.args[0]
        kwargs = pattern_def.kwargs
      tested_pattern = jsonpattern.Pattern(pattern_str, **kwargs)

    # Assume the test is passing
    # TODO: Maybe show some other metrics
    captured = tested_pattern.match(s).data

    self.verifications.append((tested_pattern, s, captured))

    self.counter += 1

  def _WriteFile(self, filename, contents):
    filename = os.path.join(self.output_dir, filename)

    f = open(filename, 'w')
    f.write(contents)
    f.close()

    # TODO: Need a logger?
    print 'Wrote %s' % filename


  # For now, we don't need anything for these

  def ParseTree(self, pattern):
    pass

  def NoMatch(self, pattern, s):
    pass

  def CompilationError(self, exception, *args, **kwargs):
    pass
